#pragma once

namespace AVUI {

class WeakReference
{
    template<class T>
    friend class TFieldScopeLock;

    friend class Object;
public:
    WeakReference() : m_pWeakReferenceNext(NULL), m_pWeakReferencePrevious(NULL), m_p(NULL), m_lockField(0) { }

    ~WeakReference()
    {
        if(m_p != NULL)
        {
            set_Target(NULL);
        }
    }

protected:

    void InvalidateTarget()
    {
        TFieldScopeLock<WeakReference> scopeLock(this);

        m_pWeakReferenceNext = m_pWeakReferencePrevious = NULL;
        m_p = NULL;
    }

    TRefCountedPtr<Object> get_Target() const 
    {
        TFieldScopeLock<WeakReference> scopeLock((WeakReference*)this);

        if(m_p == NULL)
        {
            return NULL;
        }

        while(true)
        {
            long cRef = m_p->m_cRef;

            if(cRef == 0)
            {
                return NULL;
            }

            if(AVUI_INTERLOCKED_COMPARE_EXCHANGE(m_p->m_cRef, cRef + 1, cRef) == cRef)
            {
                break;
            }
        }
        return TRefCountedPtr<Object>((Object*)m_p, false);
    }

    void set_Target(Object* p)
    {
        TFieldScopeLock<WeakReference> scopeLock(this);

        if(m_p != NULL)
        {
            m_p->RemoveWeakReference(this);
        }

        m_p = p;

        if(m_p != NULL)
        {
            m_p->AddWeakReference(this);
        }
    }

    Object* get_UnsafeTarget() const { return m_p; }

private:

    volatile long m_lockField;

    Object* m_p;
    WeakReference* m_pWeakReferenceNext;
    WeakReference* m_pWeakReferencePrevious;

};

template <class T>
class TWeakPtr : public WeakReference
{
public:

	TWeakPtr()
	{
	}
	TWeakPtr(T* p)
	{
        set_Target(p);
	}
    TWeakPtr(const TWeakPtr<T>& other)
    {
        set_Target((T*)(other.get_Target().get_Ptr()));
    }
    TRefCountedPtr<T> operator->() const
    {
        return get_Target();
    }
	operator T*() const
	{
		return (T*)get_UnsafeTarget();
	}
	bool operator!() const
	{
		return get_UnsafeTarget() == NULL;
	}
	bool operator==(T* pT) const
	{
		return ((T*)get_UnsafeTarget()) == pT;
	}
    bool operator!=(T* pT) const
    {
        return ((T*)get_UnsafeTarget()) != pT;
    }

    T* operator=(T* p)
    {
        set_Target(p);
        return p;
    }

    T* operator=(const TWeakPtr<T>& p)
    {
        TRefCountedPtr<T> pTarget = p.get_Target();
        set_Target(pTarget);
        return pTarget;
    }

    TRefCountedPtr<T> get_Target() const { return (T*)(WeakReference::get_Target().get_Ptr()); }
    void set_Target(T* pT) { WeakReference::set_Target((Object*)pT); }
};

typedef TWeakPtr<Object> ObjectWeakPtr;

};

